﻿Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
Imports System.CodeDom
Imports System.Resources
Imports System.Globalization


''' <summary>
''' Resource manager which read resource information from the database.
''' </summary>
''' <remarks></remarks>
Public Class LocalizerComponentResourceManager
    Inherits ComponentResourceManager

    Private _type As Type
    Private _loadingBaseResourceSet As Integer
    Private _resourceSets As New Dictionary(Of String, ResourceSet)

    ''' <summary>
    ''' Gets the localizer.
    ''' </summary>
    ''' 
    Public ReadOnly Property Localizer As Localizer
        Get
            Return _localizer
        End Get
    End Property
    Private _localizer As Localizer


    ''' <summary>
    ''' Initializes a new instance of the <see cref="LocalizerComponentResourceManager" /> class.
    ''' </summary>
    ''' <param name="type">The type.</param>
    Sub New(type As Type)
        MyBase.New(type)
        _type = type
    End Sub

    Public Sub LoadTranslations()
        If _localizer Is Nothing Then
            _localizer = New Localizer()
            _localizer.LoadAllTranslationsWithBaseKey(_type.FullName & ".")
        End If
    End Sub

    ''' <summary>
    ''' Provides the implementation for finding a <see cref="T:System.Resources.ResourceSet" />.
    ''' </summary>
    ''' <param name="culture">The <see cref="T:System.Globalization.CultureInfo" /> to look for.</param>
    ''' <param name="createIfNotExists">If true and if the <see cref="T:System.Resources.ResourceSet" /> has not been loaded yet, load it.</param>
    ''' <param name="tryParents">If the <see cref="T:System.Resources.ResourceSet" /> cannot be loaded, try parent <see cref="T:System.Globalization.CultureInfo" /> objects to see if they exist.</param>
    ''' <returns>
    ''' The specified <see cref="T:System.Resources.ResourceSet" />.
    ''' </returns>
    ''' <exception cref="T:System.Resources.MissingManifestResourceException">
    ''' The main assembly does not contain a .resources file and it is required to look up a resource.
    '''   </exception>
    '''   <exception cref="T:System.ExecutionEngineException">
    ''' There was an internal error in the runtime.
    '''   </exception>
    '''   <exception cref="T:System.Resources.MissingSatelliteAssemblyException">
    ''' The satellite assembly associated with <paramref name="culture" /> could not be located.
    '''   </exception>
    Protected Overrides Function InternalGetResourceSet(culture As System.Globalization.CultureInfo, createIfNotExists As Boolean, tryParents As Boolean) As ResourceSet
        LoadTranslations()
        If _resourceSets.ContainsKey(culture.Name) Then
            Return _resourceSets(culture.Name)
        End If
        '_loadingBaseResourceSet += 1
        Dim internalResourceSet = MyBase.InternalGetResourceSet(culture, createIfNotExists, tryParents)
        '_loadingBaseResourceSet -= 1
        'If _loadingBaseResourceSet > 0 Then Return internalResourceSet
        Dim rs As New LocalizerResourceSet(_localizer, _type.FullName, internalResourceSet)
        _resourceSets.Add(culture.Name, rs)
        Return rs

    End Function


End Class

Public Class LocalizerResourceManager
    Inherits ResourceManager

    Private _loadingBaseResourceSet As Integer
    Private _baseName As String
    Private _resourceSets As New Dictionary(Of String, ResourceSet)

    ''' <summary>
    ''' Gets the NLS.
    ''' </summary>
    ''' 
    Public ReadOnly Property Localizer As Localizer
        Get
            Return _localizer
        End Get
    End Property
    Private _localizer As Localizer

    ''' <summary>
    ''' Initializes a new instance of the <see cref="LocalizerResourceManager" /> class.
    ''' </summary>
    ''' <param name="type">The type.</param>
    Sub New(type As Type)
        MyBase.New(type)
        _baseName = type.FullName
    End Sub


    ''' <summary>
    ''' Initializes a new instance of the <see cref="LocalizerResourceManager" /> class.
    ''' </summary>
    ''' <param name="baseName">Name of the base.</param>
    ''' <param name="assembly">The assembly.</param>
    Sub New(baseName As String, assembly As System.Reflection.Assembly)
        MyBase.New(baseName, assembly)
        _baseName = baseName
    End Sub

    Public Sub LoadTranslations()
        If _localizer Is Nothing Then
            _localizer = New Localizer()
            _localizer.LoadAllTranslationsWithBaseKey(_baseName & ".")
        End If
    End Sub

    ''' <summary>
    ''' Provides the implementation for finding a <see cref="T:System.Resources.ResourceSet" />.
    ''' </summary>
    ''' <param name="culture">The <see cref="T:System.Globalization.CultureInfo" /> to look for.</param>
    ''' <param name="createIfNotExists">If true and if the <see cref="T:System.Resources.ResourceSet" /> has not been loaded yet, load it.</param>
    ''' <param name="tryParents">If the <see cref="T:System.Resources.ResourceSet" /> cannot be loaded, try parent <see cref="T:System.Globalization.CultureInfo" /> objects to see if they exist.</param>
    ''' <returns>
    ''' The specified <see cref="T:System.Resources.ResourceSet" />.
    ''' </returns>
    ''' <exception cref="T:System.Resources.MissingManifestResourceException">
    ''' The main assembly does not contain a .resources file and it is required to look up a resource.
    '''   </exception>
    '''   <exception cref="T:System.ExecutionEngineException">
    ''' There was an internal error in the runtime.
    '''   </exception>
    '''   <exception cref="T:System.Resources.MissingSatelliteAssemblyException">
    ''' The satellite assembly associated with <paramref name="culture" /> could not be located.
    '''   </exception>
    Protected Overrides Function InternalGetResourceSet(culture As System.Globalization.CultureInfo, createIfNotExists As Boolean, tryParents As Boolean) As ResourceSet
        LoadTranslations()
        If _resourceSets.ContainsKey(culture.Name) Then
            Return _resourceSets(culture.Name)
        End If
        '_loadingBaseResourceSet += 1
        Dim internalResourceSet = MyBase.InternalGetResourceSet(culture, createIfNotExists, tryParents)
        '_loadingBaseResourceSet -= 1
        'If _loadingBaseResourceSet > 0 Then Return internalResourceSet
        Dim rs As New LocalizerResourceSet(_localizer, _baseName, internalResourceSet)
        _resourceSets.Add(culture.Name, rs)
        Return rs
    End Function


End Class


Public Class LocalizerResourceSet
    Inherits ResourceSet

    Private _localizer As Localizer
    Private _baseNameField As String
    Private _baseResourceSet As ResourceSet

    Sub New(localizer As Localizer, baseNameField As String, baseResourceSet As ResourceSet)
        _localizer = localizer
        _baseNameField = baseNameField
        _baseResourceSet = baseResourceSet
    End Sub

    Public Overrides Function GetEnumerator() As System.Collections.IDictionaryEnumerator
        Return New LocalizerResourceSetEnumerator(_localizer, _baseNameField, _baseResourceSet.GetEnumerator())
    End Function


    Public Overrides Function GetObject(name As String) As Object
        Dim value = _baseResourceSet.GetObject(name)
        If value IsNot Nothing AndAlso value.GetType() IsNot GetType(String) Then Return value
        Dim key As String = _baseNameField & "." & name.ToString()
        If _localizer.ContainsKey(key) Then
            Return _localizer(key)
        ElseIf value IsNot Nothing Then
            _localizer.AddKey(key, CStr(value))
        End If
        Return value
    End Function

    Public Overrides Function GetObject(name As String, ignoreCase As Boolean) As Object
        Dim value = _baseResourceSet.GetObject(name, ignoreCase)
        If value IsNot Nothing AndAlso value.GetType() IsNot GetType(String) Then Return value
        Dim key As String = _baseNameField & "." & name.ToString()
        If _localizer.ContainsKey(key) Then
            Return _localizer(key)
        ElseIf value IsNot Nothing Then
            _localizer.AddKey(key, CStr(value))
        End If
        Return value
    End Function

    Public Overrides Function GetString(name As String) As String
        Dim value = _baseResourceSet.GetString(name)
        Dim key As String = _baseNameField & "." & name.ToString()
        If _localizer.ContainsKey(key) Then
            Return _localizer(key)
        ElseIf value IsNot Nothing Then
            _localizer.AddKey(key, CStr(value))
        End If
        Return value
    End Function

    Public Overrides Function GetString(name As String, ignoreCase As Boolean) As String
        Dim value = _baseResourceSet.GetString(name, ignoreCase)
        Dim nlsKey As String = _baseNameField & "." & name.ToString()
        If _localizer.ContainsKey(nlsKey) Then
            Return _localizer(nlsKey)
        ElseIf value IsNot Nothing Then
            _localizer.AddKey(nlsKey, CStr(value))
        End If
        Return value
    End Function


    Private Class LocalizerResourceSetEnumerator
        Implements IDictionaryEnumerator

        Private _localizer As Localizer
        Private _baseEnumerator As IDictionaryEnumerator
        Private _baseNameField As String

        Sub New(localizer As Localizer, baseNameField As String, baseEnumerator As IDictionaryEnumerator)
            _localizer = localizer
            _baseNameField = baseNameField
            _baseEnumerator = baseEnumerator
        End Sub

        Public ReadOnly Property Entry As System.Collections.DictionaryEntry Implements System.Collections.IDictionaryEnumerator.Entry
            Get
                Dim e = _baseEnumerator.Entry
                Return e
            End Get
        End Property

        Public ReadOnly Property Key As Object Implements System.Collections.IDictionaryEnumerator.Key
            Get
                Dim k = _baseEnumerator.Key
                Return k
            End Get
        End Property

        Public ReadOnly Property Value As Object Implements System.Collections.IDictionaryEnumerator.Value
            Get
                Dim val = _baseEnumerator.Value
                Return val
            End Get
        End Property

        Public ReadOnly Property Current As Object Implements System.Collections.IEnumerator.Current
            Get
                Dim cur = CType(_baseEnumerator.Current, DictionaryEntry)
                If cur.Key.ToString().StartsWith(">") OrElse (cur.Value IsNot Nothing AndAlso cur.Value.GetType() IsNot GetType(String)) Then
                    Return cur
                End If
                Dim key As String = _baseNameField & "." & cur.Key.ToString()
                If _localizer.ContainsKey(key) Then
                    cur.Value = _localizer(key)
                ElseIf cur.Value IsNot Nothing Then
                    _localizer.AddKey(key, CStr(cur.Value))
                End If
                Return cur
            End Get
        End Property

        Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
            Return _baseEnumerator.MoveNext()
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            _baseEnumerator.Reset()
        End Sub
    End Class

End Class